/*
Abstract:
  Different compile-time tools

Last changed:
  $Id: tools.h 67 2009-04-13 08:26:23Z vitamin.caig $

Author:
  (C) Vitamin/CAIG/2001

  This file is the part of Textator project
*/
#ifndef __TOOL_H_DEFINED__
#define __TOOL_H_DEFINED__

#include <sstream>
#include <algorithm>
#include <functional>

template<class T>
struct HexOut
{
  explicit HexOut(const T& p) : Param(p)
  {
  }

  const T& Param;
};

template<class T>
inline HexOut<T> Hex(const T& p)
{
  return HexOut<T>(p);
}

template<class S>
struct ToString
{
  template<class P>
  inline static S Convert(const P& param)
  {
    std::basic_ostringstream<typename S::value_type> str;
    str << param;
    return str.str();
  }

  template<class P>
  inline static S Convert(const HexOut<P>& param)
  {
    std::basic_ostringstream<typename S::value_type> str;
    str << '0' << 'x';
    str.width(sizeof(P) * 2);
    str.fill('0');
    str.flags(std::ios::hex | std::ios::right);
    str << param.Param;
    return str.str();
  }

  inline static S Convert(const S& param)
  {
    return param;
  }
};

template<class S>
inline void ReplaceInString(S& str, const S& pattern, const S& change)
{
  for (typename S::size_type pos = str.find(pattern); S::npos != pos; pos = str.find(pattern, pos + change.size()))
  {
    str.replace(pos, pattern.size(), change);
  }
}

template<class S, class C>
inline void SplitString(const S& input, const S& delimiters, C& container)
{
  typedef typename S::size_type index;
  index beg(input.find_first_not_of(delimiters));
  while (beg != S::npos)
  {
    const index end(input.find_first_of(delimiters, beg));
    container.push_back(input.substr(beg, end));
    beg = input.find_first_not_of(delimiters, end);
  }
}

template<class S, class P, class C>
inline void SplitString(const S& input, P pred, C& container)
{
  typedef typename S::const_iterator iterator;
  const iterator lim(input.end());
  iterator beg(std::find_if(input.begin(), lim, std::not1(pred)));
  while (beg != lim)
  {
    const iterator end(std::find_if(beg, lim, pred));
    container.push_back(S(beg, end));
    beg = std::find_if(end, lim, std::not1(pred));
  }
}

template<class S>
class StrIterator
{
  StrIterator<S>& operator = (const StrIterator<S>&);
public:
  explicit StrIterator(const S& str) : It(str.begin()), Lim(str.end())
  {
  }
  typename S::value_type operator * () const
  {
    return *It;
  }
  operator bool () const
  {
    return It != Lim;
  }
  bool operator ! () const
  {
    return It == Lim;
  }
  StrIterator<S>& operator ++ ()
  {
    ++It;
    return *this;
  }
private:
  typename S::const_iterator It;
  const typename S::const_iterator Lim;
};

template<class T, std::size_t D>
inline const T* ArrayEnd(const T (&arr)[D])
{
  return arr + D;
}

class NonInstantiable
{
protected:
  NonInstantiable();
  ~NonInstantiable();
private:
  NonInstantiable(const NonInstantiable&);
  const NonInstantiable& operator = (const NonInstantiable&);
};

template<class T>
class RefWrapper : public std::unary_function<typename T::argument_type, typename T::result_type>
{
  RefWrapper& operator = (const RefWrapper<T>& rw);
public:
  explicit RefWrapper(T& ref) : Ref(ref)
  {
  }
  RefWrapper(const RefWrapper<T>& rw) : Ref(rw.Ref)
  {
  }

  typename T::result_type operator ()(typename T::argument_type arg)
  {
    return Ref(arg);
  }
private:
  T& Ref;
};

template<class T>
inline RefWrapper<T> RefWrap(T& ref)
{
  return RefWrapper<T>(ref);
}

template<class T, class F>
inline T safe_ptr_cast(F* from)
{
  return static_cast<T>(static_cast<void*>(from));
}

template<class T, class F>
inline T safe_ptr_cast(const F* from)
{
  return static_cast<T>(static_cast<const void*>(from));
}

#endif //__TOOL_H_DEFINED__
